package com.msgqu.share.utils;

import com.msgqu.share.consts.MsgConst;
import com.msgqu.share.domain.common.MinioUploadResult;
import com.msgqu.share.exception.SharedException;
import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @author: wsj
 * @create: 2020-11-25 17:43
 * @throws:
 */
@Slf4j
public final class MinioUtil {
    /**文件地址下载url过期时间 默认7天*/
    public static final int EXPIR_TIME = (int) TimeUnit.DAYS.toSeconds(7);


    /**
     * @description: 下载文件
     * @params: [response, bucketName, pathName]
     * @return: void
     * @author: wsj
     * @create: 2020-11-26 14:25
     * @throws
     */
    public static void download(HttpServletResponse response, String bucketName, String pathName,String filename){
        InputStream inputStream = getObject(bucketName, pathName);
        OutputStream outputStream = null;
        try {
            response.addHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
            response.setContentType("application/force-download");
            outputStream = response.getOutputStream();
            byte[] b = new byte[1024];
            int length;
            while((length = inputStream.read(b)) != -1 ) {
                outputStream.write(b,0,length);
            }
        }catch (Exception e){
            throw new SharedException(HttpStatus.INTERNAL_SERVER_ERROR.value(),MsgConst.MINIO_DOWNLOAD_ERROR);
        }finally {
            if(outputStream != null){
                try {
                    outputStream.close();
                } catch (Exception e){
                   log.error("----------关闭输出流异常",e);
                }
            }
            if(inputStream != null){
                try {
                    inputStream.close();
                } catch (Exception e){
                    log.error("----------关闭输入流异常",e);
                }
            }
        }
    }

    /**
     * @description: 获取指定二进制文件流
     * @params: [bucketName, pathName]
     * @return: java.io.InputStream
     * @author: wsj
     * @create: 2020-11-26 13:59
     * @throws
     */
    public static InputStream getObject(String bucketName,String pathName){
        try {
            return getMinioClient().getObject(GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(pathName).build());
        }catch (Exception e){
            throw new SharedException(HttpStatus.INTERNAL_SERVER_ERROR.value(),MsgConst.MINIO_GETOBJECT_ERROR);
        }
    }

    /**
     * @description: 删除一个对象文件
     * @params: [bucketName, pathName]
     * @return: void
     * @author: wsj
     * @create: 2020-11-26 13:52
     * @throws
     */
    public static void removeObject(String bucketName,String pathName){
        try {
            getMinioClient().removeObject(RemoveObjectArgs
                    .builder().bucket(bucketName)
                    .object(pathName).build());
        }catch (Exception e){
            throw new SharedException(HttpStatus.INTERNAL_SERVER_ERROR.value(),MsgConst.MINIO_REMOVEOBJECT_ERROR);
        }
    }

    /**
     * @description: 获取文件链接(默认是get请求链接)
     * @params: [bucketName, pathName]
     * @return: java.lang.String
     * @author: wsj
     * @create: 2020-11-26 11:05
     * @throws
     */
    public static String getPresignedObjectUrl(String bucketName,String pathName){
        return getPresignedObjectUrl(bucketName,pathName,EXPIR_TIME,Method.GET);
    }
    /**
     * @description: 获取文件链接
     * @params: [bucketName, pathName, expir 不能小于0或者大于7天, method 请求方式]
     * @return: java.lang.String
     * @author: wsj
     * @create: 2020-11-26 11:05
     * @throws
     */
    public static String getPresignedObjectUrl(String bucketName,String pathName,int expir,Method method){
        try {
            return getMinioClient().getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(method)
                    .bucket(bucketName).object(pathName)
                    .expiry(expir).build());
        }catch (Exception e){
            throw new SharedException(HttpStatus.INTERNAL_SERVER_ERROR.value(),MsgConst.MINIO_PRESIGNEDOBJECTURL_ERROR);
        }
    }
    /**
     * @description: 上传文件
     * @params: [file]
     * @return: com.msgqu.share.domain.common.MinioUploadResult
     * @author: wsj
     * @create: 2020-11-25 23:55
     * @throws
     */
    public static MinioUploadResult putObject(MultipartFile file,String bucketName){
        long size;
        if(Objects.isNull(file) || (size = file.getSize())<=0){
            throw new SharedException(HttpStatus.INTERNAL_SERVER_ERROR.value(),MsgConst.MINIO_FILE_SIZE_ERROR);
        }
        makeBucket(bucketName);
        String filename = file.getOriginalFilename();
        String filetype = filename.substring(filename.lastIndexOf(".")+1);
        String uuid = IdGeneratorUtil.getUUID();
        String minioFilename = uuid.concat(".").concat(filetype);
        //指定minio上传的路径
        SimpleDateFormat sdf = new SimpleDateFormat("YYYY/MM/dd/");
        String pathname = sdf.format(new Date()).concat(minioFilename);
        try {
            getMinioClient().putObject(PutObjectArgs.builder()
                    //文件名称重复覆盖
                    .bucket(bucketName).object(pathname)
                    .stream(file.getInputStream(), size, -1)
                    .contentType(filetype).build());
            return new MinioUploadResult(pathname,filename,uuid,bucketName);
        }catch (Exception e){
            throw new SharedException(HttpStatus.INTERNAL_SERVER_ERROR.value(),MsgConst.MINIO_PUTOBJECT_ERROR);
        }
    }
    /**
     * @description: 创建minio桶
     * @params: [bucketName]
     * @return: void
     * @author: wsj
     * @create: 2020-11-25 23:37
     * @throws
     */
    public static void makeBucket(String bucketName){
        boolean exists = bucketExists(bucketName);
        try {
            if(!exists){
                getMinioClient().makeBucket(MakeBucketArgs
                        .builder()
                        .bucket(bucketName)
                        .build());
            }
        }catch (Exception e){
            throw new SharedException(HttpStatus.INTERNAL_SERVER_ERROR.value(), MsgConst.MINIO_MAKEBUCKET_ERROR);
        }
    }
    /**
     * @description: 判断是否存在桶
     * @params: [bucketName]
     * @return: boolean
     * @author: wsj
     * @create: 2020-11-25 17:52
     * @throws
     */
    public static boolean bucketExists(String bucketName){
        try {
            return getMinioClient().bucketExists(BucketExistsArgs
                    .builder()
                    .bucket(bucketName)
                    .build());
        }catch (Exception e){
            throw new SharedException(HttpStatus.INTERNAL_SERVER_ERROR.value(), MsgConst.MINIO_BUCKETEXISTS_ERROR);
        }
    }

    /**
     * @description: 获取minioclinet
     * @params: []
     * @return: io.minio.MinioClient
     * @author: wsj
     * @create: 2020-11-25 17:48
     * @throws
     */
    public static MinioClient getMinioClient(){
        return ApplicationContextHelper.getBeanByType(MinioClient.class);
    }
}
